import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, r2_score
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Bidirectional
from tensorflow.keras.callbacks import EarlyStopping
import matplotlib.pyplot as plt

# 加载数据
df = pd.read_excel('神经网络数据.xlsx')

# 提取特征和目标变量
X = df[['箱温', 'O2', 'CO', 'CO2', ]].values
y = df['煤温'].values

# 数据标准化
scaler_X = StandardScaler()
scaler_y = StandardScaler()
X_scaled = scaler_X.fit_transform(X)
y_scaled = scaler_y.fit_transform(y.reshape(-1, 1))

# 将数据重塑为 LSTM 所需的形状 [samples, timesteps, features]
X_scaled = X_scaled.reshape((X_scaled.shape[0], 1, X_scaled.shape[1]))

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y_scaled, test_size=0.2, random_state=42)

# 构建 Bi-LSTM 模型
model = Sequential()
model.add(Bidirectional(LSTM(50, return_sequences=True), input_shape=(1, X.shape[1])))
model.add(Bidirectional(LSTM(50)))
model.add(Dense(1))

# 编译模型
model.compile(optimizer='adam', loss='mean_squared_error')

# 添加早停机制
early_stopping = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True)

# 训练模型
history = model.fit(X_train, y_train, epochs=1000, batch_size=16, validation_split=0.2, callbacks=[early_stopping])

# 评估模型
loss = model.evaluate(X_test, y_test)
print(f'Test Loss: {loss}')

# 使用模型进行预测
y_pred_scaled = model.predict(X_test)

# 将预测结果反标准化
y_pred = scaler_y.inverse_transform(y_pred_scaled)

# 将真实值反标准化
y_test_original = scaler_y.inverse_transform(y_test)

# 计算评估指标
mse = mean_squared_error(y_test_original, y_pred)
r2 = r2_score(y_test_original, y_pred)
print(f'Mean Squared Error: {mse}')
print(f'R-squared: {r2}')

# 可视化预测结果与实际值
plt.figure(figsize=(12, 6))
plt.plot(y_test_original, label='Actual Coal Temperature')
plt.plot(y_pred, label='Predicted Coal Temperature')
plt.xlabel('Sample Index')
plt.ylabel('Coal Temperature')
plt.title('Actual vs Predicted Coal Temperature')
plt.legend()
plt.show()

# 可视化训练过程中的损失曲线
plt.figure(figsize=(12, 6))
plt.plot(history.history['loss'], label='Training Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.show()

# 保存模型
model.save('coal_temperature_prediction_model.h5')

# 保存预测结果
predictions_df = pd.DataFrame({'Actual': y_test_original.flatten(), 'Predicted': y_pred.flatten()})
predictions_df.to_excel('coal_temperature_predictions.xlsx', index=False)
